package com.info.zhiduoduo.pay.sdk.dayspaysdk.util;

import com.info.zhiduoduo.pay.sdk.dayspaysdk.core.util.Strings;

import net.sf.ezmorph.object.DateMorpher;
import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import net.sf.json.JsonConfig;
import net.sf.json.util.CycleDetectionStrategy;
import net.sf.json.util.JSONUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.Writer;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;


public class JsonUtil {
	public final static String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
	/** * logger. */
	private static Log logger = LogFactory.getLog(JsonUtil.class);

	/** * ��������Ҫ�ı������췽��. */
	protected JsonUtil() {
	}

	/**
	 * write.
	 * 
	 * @param bean
	 *            obj
	 * @param writer
	 *            �����
	 * @param excludes
	 *            ��ת������������
	 * @param datePattern
	 *            date��stringת����ģʽ
	 * @throws Exception
	 *             д�����ݿ��ܳ����쳣
	 */
	public static void write(Object bean, Writer writer, String[] excludes,
			String datePattern) throws Exception {
		JsonConfig jsonConfig = configJson(excludes, datePattern);

		JSON json = JSONSerializer.toJSON(bean, jsonConfig);

		json.write(writer);
	}

	/**
	 * ����json-lib��Ҫ��excludes��datePattern.
	 * 
	 * @param excludes
	 *            ����Ҫת������������
	 * @param datePattern
	 *            ����ת��ģʽ
	 * @return JsonConfig ����excludes��dataPattern���ɵ�jsonConfig������write
	 */
	public static JsonConfig configJson(String[] excludes, String datePattern) {
		JsonConfig jsonConfig = new JsonConfig();
		jsonConfig.setExcludes(excludes);
		jsonConfig.setIgnoreDefaultExcludes(false);
		jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
		jsonConfig.registerJsonValueProcessor(Date.class,
				new DateJsonValueProcessor(datePattern));
		jsonConfig.registerJsonValueProcessor(Timestamp.class,
				new DateJsonValueProcessor(datePattern));
		return jsonConfig;
	}

	public static String toJson(Object obj) {
		String json = JSONObject.fromObject(obj,
				configJson(new String[] {}, DEFAULT_DATETIME_FORMAT))
				.toString();
		return json;
	}
	
	public static Object jsonToBean(String json, Class cls) {
		if(json == null || (!json.startsWith("{"))){
			logger.info("bad json:"+json);			
		}
		String[] formats = {"yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd HH:mm:ss"};
		JSONUtils.getMorpherRegistry().registerMorpher(new DateMorpher(formats) );
		JSONObject jsonObject = JSONObject.fromObject(json);
		return JSONObject.toBean(jsonObject, cls);
	}

	public static String toJsonArray(Object obj) {
		String json = JSONArray.fromObject(obj,
				configJson(new String[] {}, DEFAULT_DATETIME_FORMAT))
				.toString();
		return json;
	}
	
	/**
	 * data={"id":"1"}��json�����ݴ���ָ����pojo.
	 * 
	 * @param <T>
	 *            Object
	 * @param data
	 *            json�ַ���
	 * @param clazz
	 *            ��Ҫת����bean�ľ�������
	 * @param excludes
	 *            ����Ҫת������������
	 * @param datePattern
	 *            ����ת��ģʽ
	 * @return T
	 * @throws Exception
	 *             java.lang.InstantiationException,
	 *             java.beans.IntrospectionException,
	 *             java.lang.IllegalAccessException
	 */
	public static <T extends Object> T json2Bean(String data, Class<T> clazz,
			String[] excludes, String datePattern) throws Exception {
		// JsonUtils.configJson(excludes, datePattern);
		T entity = clazz.newInstance();

		return json2Bean(data, entity, excludes, datePattern);
	}

	/**
	 * data={"id":"1"}��json������ݣ����ָ����pojo.
	 * 
	 * @param <T>
	 *            Object
	 * @param data
	 *            json�ַ���
	 * @param entity
	 *            ��Ҫ������ݵ�bean
	 * @param excludes
	 *            ����Ҫת������������
	 * @param datePattern
	 *            ����ת��ģʽ
	 * @return T
	 * @throws Exception
	 *             java.lang.InstantiationException,
	 *             java.beans.IntrospectionException,
	 *             java.lang.IllegalAccessException
	 */
	public static <T extends Object> T json2Bean(String data, T entity,
			String[] excludes, String datePattern) throws Exception {
		// JsonUtils.configJson(excludes, datePattern);
		if(data == null || (!data.startsWith("{"))){
			logger.info("bad json:"+data);			
		}
		
		JSONObject jsonObject = JSONObject.fromObject(data);

		return json2Bean(jsonObject, entity, excludes, datePattern);
	}

	/**
	 * ����Class����entity���ٰ�JSONObject�е���������ȥ.
	 * 
	 * @param <T>
	 *            Object
	 * @param jsonObject
	 *            json����
	 * @param clazz
	 *            ��Ҫת����bean�ľ�������
	 * @param excludes
	 *            ����Ҫת������������
	 * @param datePattern
	 *            ����ת��ģʽ
	 * @return T
	 * @throws Exception
	 *             java.lang.InstantiationException,
	 *             java.beans.IntrospectionException,
	 *             java.lang.IllegalAccessException
	 */
	public static <T extends Object> T json2Bean(JSONObject jsonObject,
			Class<T> clazz, String[] excludes, String datePattern)
			throws Exception {
		// JsonUtils.configJson(excludes, datePattern);
		T entity = clazz.newInstance();

		return json2Bean(jsonObject, entity, excludes, datePattern);
	}

	/**
	 * ��JSONObject�е�������䵽entity��.
	 * 
	 * @param <T>
	 *            Object
	 * @param jsonObject
	 *            json����
	 * @param entity
	 *            ��Ҫ������ݵ�node
	 * @param excludes
	 *            ����Ҫת������������
	 * @param datePattern
	 *            ����ת��ģʽ
	 * @return T
	 * @throws Exception
	 *             java.lang.InstantiationException,
	 *             java.beans.IntrospectionException,
	 *             java.lang.IllegalAccessException
	 */
	public static <T extends Object> T json2Bean(JSONObject jsonObject,
			T entity, String[] excludes, String datePattern) throws Exception {
		// JsonUtils.configJson(excludes, datePattern);
		Set<String> excludeSet = new HashSet<String>();

		for (String exclude : excludes) {
			excludeSet.add(exclude);
		}

		for (Object object : jsonObject.entrySet()) {
			Map.Entry entry = (Map.Entry) object;
			String propertyName = entry.getKey().toString();

			if (excludeSet.contains(propertyName)) {
				continue;
			}

			String propertyValue = entry.getValue().toString();

			try {
				PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
						propertyName, entity.getClass());
				Class propertyType = propertyDescriptor.getPropertyType();

				Method writeMethod = propertyDescriptor.getWriteMethod();

				if (propertyType == String.class) {
					writeMethod.invoke(entity, propertyValue);
				} else if ((propertyType == Byte.class)
						|| (propertyType == byte.class)) {
					writeMethod.invoke(entity, Byte.parseByte(propertyValue));
				} else if ((propertyType == Short.class)
						|| (propertyType == short.class)) {
					writeMethod.invoke(entity, Short.parseShort(propertyValue));
				} else if ((propertyType == Integer.class)
						|| (propertyType == int.class)) {
					writeMethod.invoke(entity, Integer.parseInt(propertyValue));
				} else if ((propertyType == Long.class)
						|| (propertyType == long.class)) {
					writeMethod.invoke(entity, Long.parseLong(propertyValue));
				} else if ((propertyType == Float.class)
						|| (propertyType == float.class)) {
					writeMethod.invoke(entity, Float.parseFloat(propertyValue));
				} else if ((propertyType == Double.class)
						|| (propertyType == double.class)) {
					writeMethod.invoke(entity, Double
							.parseDouble(propertyValue));
				} else if ((propertyType == Boolean.class)
						|| (propertyType == boolean.class)) {
					writeMethod.invoke(entity, Boolean
							.parseBoolean(propertyValue));
				} else if ((propertyType == Character.class)
						|| (propertyType == char.class)) {
					writeMethod.invoke(entity, propertyValue.charAt(0));
				} else if (propertyType == Date.class) {
					SimpleDateFormat dateFormat = new SimpleDateFormat(
							datePattern);
					writeMethod.invoke(entity, dateFormat.parse(propertyValue));
				}
			} catch (IntrospectionException ex) {
				logger.info(ex);

				continue;
			}
		}

		return entity;
	}

	/**
	 * data=[{"id":"1"},{"id":2}]��json������ݣ�����pojo����.
	 * 
	 * @param <T>
	 *            Object
	 * @param data
	 *            json�ַ���
	 * @param clazz
	 *            ��Ҫת����node�ľ�������
	 * @param excludes
	 *            ����Ҫת������������
	 * @param datePattern
	 *            ����ת��ģʽ
	 * @return List
	 * @throws Exception
	 *             java.lang.InstantiationException,
	 *             java.beans.IntrospectionException,
	 *             java.lang.IllegalAccessException
	 */
	public static <T extends Object> List<T> json2List(String data,
			Class<T> clazz, String[] excludes, String datePattern)
			throws Exception {
		if(data == null || (!data.startsWith("{"))){
			logger.info("bad json:"+data);			
		}
		
		JSONArray jsonArray = JSONArray.fromObject(data);

		return json2List(jsonArray, clazz, excludes, datePattern);
	}
	
	public static List<Map<String, String>> json2MapList(String data)
			throws Exception {
		JSONArray jsonArray = JSONArray.fromObject(data);
		List<Map<String, String>> results = new ArrayList<Map<String, String>>();
		for (int i = 0; i < jsonArray.size(); i++) {
			JSONObject jsonObject = jsonArray.getJSONObject(i);
			Map<String, String> dataMap = JsonUtil.json2StringMap(jsonObject.toString());
			results.add(dataMap);
		}
		return results;
	}

	/**
	 * data=[{"id":"1"},{"id":2}]��json������ݣ�����pojo����.
	 * 
	 * @param <T>
	 *            Object
	 * @param jsonArray
	 *            JSONArray
	 * @param clazz
	 *            ��Ҫת����node�ľ�������
	 * @param excludes
	 *            ����Ҫת������������
	 * @param datePattern
	 *            ����ת��ģʽ
	 * @return List
	 * @throws Exception
	 *             java.lang.InstantiationException,
	 *             java.beans.IntrospectionException,
	 *             java.lang.IllegalAccessException
	 */
	public static <T extends Object> List<T> json2List(JSONArray jsonArray,
			Class<T> clazz, String[] excludes, String datePattern)
			throws Exception {
		List<T> list = new ArrayList<T>();

		for (int i = 0; i < jsonArray.size(); i++) {
			JSONObject jsonObject = jsonArray.getJSONObject(i);
			T node = json2Bean(jsonObject, clazz, excludes, datePattern);
			list.add(node);
		}

		return list;
	}
	
	public static Map<String, Object> json2Map(String json){
		//JSONObject������"{"��ͷ  
		if(json == null || (!json.startsWith("{"))){
			logger.info("bad json:"+json);			
		}
		JSONObject jsonObject=JSONObject.fromObject(json);
        Map<String, Object> resultMap = new HashMap<String, Object>();  
        Iterator<String> iter = jsonObject.keys();  
        String key=null;  
        Object value=null;  
        while (iter.hasNext()) {  
            key=iter.next();  
            value=jsonObject.get(key);  
            resultMap.put(key, value);  
        }
        return resultMap;
	}
	
	public static Map<String, String> json2StringMap(String json){
		//JSONObject������"{"��ͷ  
		JSONObject jsonObject=JSONObject.fromObject(json);
        Map<String, String> resultMap = new HashMap<String, String>();  
        Iterator<String> iter = jsonObject.keys();  
        String key=null;  
        Object value=null;  
        while (iter.hasNext()) {  
            key=iter.next();  
            value=jsonObject.get(key);  
            resultMap.put(key, Strings.trim(value));
        }
        return resultMap;
	}

	
	public static Map<String, String> json2NoTrimStringMap(String json){
		//JSONObject������"{"��ͷ  
		if(json == null || (!json.startsWith("{"))){
			logger.info("bad json:"+json);			
		}
		JSONObject jsonObject=JSONObject.fromObject(json);
        Map<String, String> resultMap = new HashMap<String, String>();  
        Iterator<String> iter = jsonObject.keys();  
        String key=null;  
        Object value=null;  
        while (iter.hasNext()) {  
            key=iter.next();  
            value=jsonObject.get(key);  
            if(null == value){
                resultMap.put(key, null);  
            } else {
                resultMap.put(key, value.toString()); 
            }
        }
        return resultMap;
	}
	
	public static String getValueFromJsonStr(String json, String key){
		if(json == null || (!json.startsWith("{"))){
			logger.info("bad json:"+json);
			return "";			
		}
		String value = "";
		try {
			JSONObject jsonObject = JSONObject.fromObject(json);
			value = jsonObject.optString(key);
		} catch(JSONException e){
			logger.error(Strings.toString(e));
		} catch(Exception e){
			logger.error("getValueFromJsonStr", e);
		}
		return value;
	}
	
	public static String setValueToJsonStr(String json, String key, String value){
		if(json == null || (!json.startsWith("{"))){
			logger.info("bad json:"+json);			
		}
		String jsonStr = "";
		try {
			if(Strings.isNullOrEmpty(json)){
				json = "{}";
			}
			JSONObject jsonObject = JSONObject.fromObject(json);
			jsonObject.put(key, value);
			jsonStr = jsonObject.toString();
		} catch(JSONException e){
			logger.error(e.getMessage());
		} catch(Exception e){
			logger.error("getValueFromJsonStr", e);
		}
		return jsonStr;
	}
	
	public static String[] getValuesFromJsonStr(String json, String[] keys){
		if(json == null || (!json.startsWith("{"))){
			logger.info("bad json:"+json);			
		}
		String[] values = new String[keys.length];
		try {
			JSONObject jsonObject = JSONObject.fromObject(json);
			for(int i=0; i<keys.length; i++){
				values[i] = jsonObject.optString(keys[i]);
			}
		} catch(JSONException e){
			logger.error(e.getMessage());
		} catch(Exception e){
			logger.error("getValueFromJsonStr", e);
		}
		return values;
	}
	
	public static String setValuesToJsonStr(String json, String[] keys, String[] values){
		if(json == null || (!json.startsWith("{"))){
			logger.info("bad json:"+json);			
		}
		String jsonStr = "";
		try {
			if(Strings.isNullOrEmpty(json)){
				json = "{}";
			}
			JSONObject jsonObject = JSONObject.fromObject(json);
			for(int i=0; i<keys.length; i++){
				jsonObject.put(keys[i], values[i]);
			}
			jsonStr = jsonObject.toString();
		} catch(JSONException e){
			logger.error(e.getMessage());
		} catch(Exception e){
			logger.error("getValueFromJsonStr", e);
		}
		return jsonStr;
	}
	
	public static boolean isGoodJson(String json) {  
        if (Strings.isNullOrEmpty(json)) {  
            return false;  
        }  
        try {  
        	JSONObject jsonObject = JSONObject.fromObject(json);
            return true;  
        } catch (Exception e) {  
            logger.error("isBadJson");
            return false;  
        }  
    }
	
	public static void main(String[] args) throws Exception{
		String channelInfo = "123456";
		String[] keys = {"code", "msg"};
		String[] values = {"0000", "֧���ɹ�"};
		String json = JsonUtil.setValuesToJsonStr(channelInfo, keys, values);
		System.out.println(json);
	}

}
